package com.thoughtservice.jspdoc;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Future;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang.time.DurationFormatUtils;
import org.apache.commons.lang.time.StopWatch;
import org.apache.log4j.MDC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.thoughtservice.jspdoc.customize.Customizer;
import com.thoughtservice.jspdoc.executors.JSPDocExecutor;
import com.thoughtservice.jspdoc.export.Exporter;
import com.thoughtservice.jspdoc.output.GenerateHtmlStructure;

public class JSPDoc {

	private static final Logger LOG = LoggerFactory.getLogger(JSPDoc.class);
	/**
	 * Starts the application.
	 * @param args an array of command-line arguments
	 */	
	public static void main(java.lang.String[] args) {		
		
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();

		// Get the command line arguments		
		if (args.length != 4) {
			LOG.error("usage:DirTree [sourceDir] [outputDir] " +
                             "[Fully qualified customizer class name, or 'null' for none] " +
                             "[Fully qualified exporter class name, or 'null' for none] ");
			return;
		}
		
		String sourceDir;
		if (args[0].equals("")) {
			sourceDir = "C:/Users/m/Documents/workspace-sts-2.9.2.RELEASE/testweb";
			LOG.info("Using default source dir: " + sourceDir);
		} else {
			File f = new File(args[0]);
			try {
				sourceDir = f.getCanonicalPath();
			} catch (IOException e) {
				LOG.error(ExceptionUtils.getFullStackTrace(e));
				return;
			}
		}
		
		String outputDir;
		if (args[1].equals("")) {
			outputDir = "C:/generated-doc";
			LOG.info("Using default output dir: " + outputDir);
		} else {
			File f = new File(args[1]);
			try {
				if(f.exists()){
					outputDir = f.getCanonicalPath();
				} else {
					//Create a dir
					FileUtils.forceMkdir(f);
					outputDir = f.getCanonicalPath();
				}
				
			} catch (IOException e) {
				LOG.error(ExceptionUtils.getFullStackTrace(e));
				return;
			}
		}

		
		Customizer Cust;
		String className = args[2];
		if (className.equals("") || className.equals("null")) {
			Cust = null;
		} else {
			try {				
				Class c = Class.forName(className);
				Cust = (Customizer) c.newInstance();
				Class [] interfaces = Cust.getClass().getInterfaces();
				boolean found = false;
				for (int i = 0; i < interfaces.length; i ++) {
					Class inf = interfaces[i];
					LOG.debug("Customizer {} ", inf.getName());
					if (inf.getName().equals("ca.yourdecor.jspdoc.customize.Customizer")) {
						found = true;
						break;
					}
				}
				
				if (! found) {
					LOG.error("Your Customizer doesn't implement the ca.yourdecor.jspdoc.customize.Customizer interface: {}", className);
					return;
				}
			} catch (ClassNotFoundException e) {
				LOG.error("Can't find your customizer class: {}", className);
				LOG.error(ExceptionUtils.getFullStackTrace(e));
				return;
			} catch (Exception e) {
				LOG.error("Can't instantiate your customizer class: {}", className);
				LOG.error(ExceptionUtils.getFullStackTrace(e));
				return;
			}
		}

		// Get export environment variable
                Exporter Exp;
		String expClassName = args[3];
		if (expClassName.equals("") || expClassName.equals("null")) {
			Exp = null;
		} else {
			try {
				Class ec = Class.forName(expClassName);
				Exp = (Exporter) ec.newInstance();
				Class [] expInterfaces = Exp.getClass().getInterfaces();
				boolean foundExp = false;
				for (int i = 0; i < expInterfaces.length; i ++) {
					Class inf = expInterfaces[i];
					
					if (inf.getName().equals("ca.yourdecor.jspdoc.export.Exporter")) {
						foundExp = true;
						break;
					}
				}
				
				if (! foundExp) {
					LOG.error("Your Customizer doesn't implement the ca.yourdecor.jspdoc.export.Exporter interface: {}" , expClassName);
					return;
				}
			} catch (ClassNotFoundException e) {
				LOG.error("Can't find your exporter class: {}", expClassName);
				LOG.error(ExceptionUtils.getFullStackTrace(e));
				return;
			} catch (Exception e) {
				LOG.error("Can't instantiate your exporter class: {}", expClassName);
				LOG.error(ExceptionUtils.getFullStackTrace(e));
				return;
			}
		}
//----------------------


		LOG.debug("SourceDir : {}", sourceDir);		
		LOG.debug("OutputDir : {}", outputDir);		
		LOG.debug("Customizer: {}", className);		
		LOG.debug("Exporter  : {}", expClassName);		


		// Construct a new DirTree object and configure it.
		DirTree dt = new DirTree(Cust);		
		DirTree.rootSourceDir = sourceDir;
		dt.rootOutputDir = outputDir;
		
		File rootDir = new File(DirTree.rootSourceDir);

		// Build the list of JSP files to process	
		LOG.info("Building jsp page list");
		dt.jspFileList = new JSPFileList(rootDir, "");
		
		LOG.debug("Found {} directories and jsp pages to process", dt.jspFileList.listSize());		

		// Parse and examine each file to collect the information
		LOG.info("Examining jsp pages");
		Iterator<JSPPage> i = dt.jspFileList.fileList();
		JSPPage p;
		while (i.hasNext()) {
			p = (JSPPage) i.next();
			if (p.isPage()) {
				LOG.debug("Page is {}. Adding to MDC logger",p.getNameShort());				
				MDC.put("jspname", p.getNameShort());
				LOG.info("Processing {}", p.getNameShort());
				//System.out.print('.');
				dt.processPage(p);
				LOG.info("Processing completed for {}", p.getNameShort());
				MDC.remove("jspname");
			}
		}		
		
		GenerateHtmlStructure htmlStructure = new GenerateHtmlStructure(sourceDir, outputDir, dt.jspFileList);

		// Create the HTML output
		// Build the index page
		LOG.info("Creating summary pages");
		
		//Copy js scripts 
		htmlStructure.copyScriptsAndStyles();
		
		/*htmlStructure.outputSummaries();
		
		// Build the index by page name
		htmlStructure.outputIndexByPageName();

		// Build the index by directory name

		htmlStructure.outputIndexByDirName();*/
		
		//Call executors for generating output summaries
		JSPDocExecutor executor = new JSPDocExecutor();
		List<Future<Object>> futures = executor.processOutputSummaries(htmlStructure);
		
		// Process the individual pages
		LOG.info("Creating page documentation*");
		i = dt.jspFileList.fileList();
		while (i.hasNext()) {
			p = (JSPPage) i.next();			
			dt.outputPage(p, htmlStructure);
		}

                // Call export 
                if(Exp != null) {
                		LOG.info("Creating export");
                      Exp.export(dt.jspFileList, outputDir);
                }

		
       stopWatch.stop();
        LOG.info("Total time taken to generate JSP Doc {} ms", DurationFormatUtils.formatDurationHMS(stopWatch.getTime()));

		LOG.info("*JSP Doc created at {} sucessfully.", outputDir);

	}

}
